package com.demo.web.cas;

import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import org.noear.solon.annotation.Component;
import org.noear.solon.annotation.Inject;
import org.noear.solon.core.handle.Context;
import org.noear.solon.core.handle.Filter;
import org.noear.solon.core.handle.FilterChain;
import org.noear.solon.data.cache.CacheService;

import javax.net.ssl.*;
import java.net.URLEncoder;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

@Component
public class CasFilter implements Filter {
    private final static OkHttpClient httpClient = getHttps();
    @Inject(value = "cache1")
    CacheService cache1;

    @Inject(value = "${sso.valid.url}")
    String sso_valid_url;
    @Inject(value = "${sso.redirect.url}")
    String sso_redirect_url;
    @Inject(value = "${sso.sys}")
    String sso_sys;

    //这里是创建一个SSLSocketFactory,提供给上面的 .sslSocketFactory()
    private static SSLSocketFactory createSSLSocketFactory(TrustAllCerts trustAllCerts) {
        SSLSocketFactory ssfFactory = null;
        try {
            SSLContext sc = SSLContext.getInstance("TLS");
            sc.init(null, new TrustManager[]{trustAllCerts}, new SecureRandom());
            ssfFactory = sc.getSocketFactory();
        } catch (Exception e) {
        }

        return ssfFactory;
    }

    //创建信任所有证书的OkHttpClient
    public static OkHttpClient getHttps() {

        TrustAllCerts trustAllCerts = new TrustAllCerts();
        OkHttpClient okHttpClient = new OkHttpClient.Builder()
                .hostnameVerifier(new

                                          HostnameVerifier() {

                                              @Override
                                              public boolean verify(String hostname, SSLSession session) {
                                                  return true;
                                              }


                                          })
                .sslSocketFactory(createSSLSocketFactory(trustAllCerts), trustAllCerts)
                .build();

        return okHttpClient;
    }

    @Override
    public void doFilter(Context ctx, FilterChain chain) throws Throwable {
        if (!"/sso".equals(ctx.path())) {
            chain.doFilter(ctx);
            return;
        }


        String ticket = ctx.param("ticket");

        if (ticket == null || "".equals(ticket.trim())) {
            ticket = ctx.cookie("cas-ticket");
        }

        String validate_response = null;
        //带ticket的sso链接
        if (ticket != null && !"".equals(ticket.trim())) {

            validate_response = (String) cache1.get("cas-ticket-" + ticket);
            if (validate_response == null || "".equals(validate_response.trim())) {
                Request.Builder builder = new Request.Builder();
                builder.url(sso_valid_url+"/validate?service=" + URLEncoder.encode(ctx.url(), "UTF-8") + "&ticket=" + ticket + "&renew=false");
                builder.get();
                Response response = httpClient.newCall(builder.build()).execute();
                if (response.isSuccessful() && response.body() != null) {
                    validate_response = response.body().string();

                    cache1.store("cas-ticket-" + ticket, validate_response, 60);
                }
            }
        }


        if (validate_response == null || "".equals(validate_response.trim())) {
            ctx.redirect(sso_redirect_url+"/?srcsys="+sso_sys+"&service=" + URLEncoder.encode(ctx.url(), "UTF-8"));
        } else {
            ctx.sessionSet("cas_validate_response", validate_response);
            chain.doFilter(ctx);
        }
    }

    public static class TrustAllCerts implements X509TrustManager {
        @Override
        public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
        }

        @Override
        public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
        }

        @Override
        public X509Certificate[] getAcceptedIssuers() {
            return new X509Certificate[0];
        }
    }
}
